home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume90 / util / tracktls / part02 < prev   
Encoding:
Internet Message Format  |  1990-01-20  |  40.8 KB

  1. Path: xanth!cs.odu.edu!Amiga-Request
  2. From: Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v90i030: Trackutils - utilities to allocate and copy disk tracks, Part02/02
  5. Message-ID: <11070@xanth.cs.odu.edu>
  6. Date: 20 Jan 90 15:38:03 GMT
  7. Sender: tadguy@cs.odu.edu
  8. Reply-To: Eddy Carroll <ECARROLL%vax1.tcd.ie@CUNYVM.CUNY.EDU>
  9. Lines: 1391
  10. Approved: tadguy@cs.odu.edu (Tad Guy)
  11.  
  12. Submitted-by: Eddy Carroll <ECARROLL%vax1.tcd.ie@CUNYVM.CUNY.EDU>
  13. Posting-number: Volume 90, Issue 030
  14. Archive-name: util/trackutils/part02
  15.  
  16. #!/bin/sh
  17. # This is a shell archive.  Remove anything before this line, then unpack
  18. # it by saving it into a file and typing "sh file".  To overwrite existing
  19. # files, type "sh file -c".  You can also feed this as standard input via
  20. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  21. # will see the following message at the end:
  22. #        "End of archive 2 (of 2)."
  23. # Contents:  src/tfile.c
  24. # Wrapped by tadguy@xanth on Sat Jan 20 10:37:18 1990
  25. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  26. if test -f 'src/tfile.c' -a "${1}" != "-c" ; then 
  27.   echo shar: Will not clobber existing file \"'src/tfile.c'\"
  28. else
  29. echo shar: Extracting \"'src/tfile.c'\" \(38195 characters\)
  30. sed "s/^X//" >'src/tfile.c' <<'END_OF_FILE'
  31. X/*
  32. X * TFILE.C
  33. X *
  34. X * (C) Copyright Eddy Carroll, January 1990
  35. X *
  36. X * This is a little utility which simply creates a "fake" file on a disk,
  37. X * which makes AmigaDos think that all the blocks on a given range of
  38. X * tracks are in use. I.e. it allows you to reserve a section of the disk
  39. X * for your own messing around, without fear of AmigaDos stomping over you
  40. X * at some later stage.
  41. X *
  42. X * Usage: tfile <pathname> <start> <end>
  43. X *
  44. X * <pathname>   The full pathname of the filename AmigaDOS will think
  45. X *              the blocks are stored in. This also specifies the device
  46. X *              on which the blocks are to be reserved.
  47. X *
  48. X * <start>      The starting track to reserve blocks on.
  49. X *
  50. X * <end>        The ending track to reserve blocks on.
  51. X *
  52. X * For example, to reserve tracks 70 to 79 on the disk in DF0:, you might
  53. X * give the command:
  54. X *
  55. X *      tfile df0:devs/Tracks70-79 70 79
  56. X *
  57. X * which will create the file devs/Tracks70-79 on the disk in DF0: If you
  58. X * try and actually access this file, you will find it only contains a brief
  59. X * message -- this is a safeguard to stop AmigaDOS trying to make sense
  60. X * of whatever data is actually on tracks 70 to 79.
  61. X *
  62. X * Tfile is primarily intended for use with the companion program tcopy,
  63. X * which allows tracks from a small device such as RAD: to be stored on
  64. X * part of a larger device like a floppy disk, and then read back in at
  65. X * a later time (and at high speed).
  66. X *
  67. X *
  68. X *        Note: The following assumptions are hardwired into the code --
  69. X *
  70. X *                -- Long's are at least 32 bits long
  71. X *                -- Blocks are 512 bytes long
  72. X *                -- Either the old or fast filing system is in use
  73. X */
  74. X
  75. X#define TRUE            1
  76. X#define FALSE            0
  77. X#define LASTCHAR(s)        (s[strlen(s)-1])
  78. X
  79. X#ifndef LATTICE_50
  80. X#include "system.h"
  81. X#endif
  82. X
  83. X#include "dosheaders.h"
  84. X
  85. X#define MIN(x,y) ((x) < (y) ? (x) : (y))
  86. X
  87. Xextern struct DosLibrary       *DOSBase;
  88. X
  89. Xtypedef struct IORequest       IOREQ;
  90. Xtypedef struct MsgPort         MSGPORT;
  91. Xtypedef struct Process         PROC;
  92. Xtypedef struct StandardPacket  STDPKT;
  93. X
  94. Xvoid inhibit(MSGPORT *devport, int mode);    /* Called by cleanup() */
  95. X
  96. X
  97. X/*
  98. X *        This is the message that gets stored in the dummy file when
  99. X *        the disk being written to is an OFS disk. Max 488 characters please.
  100. X */
  101. Xchar FileMessage[] = "\
  102. XThis file was created using TFile (C) Copyright Eddy Carroll 1990.\n\n\
  103. XTFile creates special files which don't contain data, but instead prevent\n\
  104. XAmigaDOS from overwriting the information on some tracks on this disk.\n\n";
  105. X
  106. X
  107. X/*
  108. X *        Structure representing a disk device
  109. X */
  110. Xtypedef struct {
  111. X    char  *devname;            /* Name of exec device for this disk    */
  112. X    int   isfloppy;            /* True if device is trackdisk.device    */
  113. X    int   isffs;            /* True if device is using FFS            */
  114. X    int   isknown;            /* True if filesystem is known            */
  115. X    ULONG unit;                /* Unit number of above exec device        */
  116. X    ULONG blocksize;        /* Number of bytes per block            */
  117. X    ULONG blockspertrack;    /* Number of blocks/sectors per track    */
  118. X    ULONG surfaces;            /* Number of tracks per cylinder        */
  119. X    ULONG lowcyl;            /* Starting cylinder of disk on device     */
  120. X    ULONG numcyl;            /* Number of cylinders on this disk        */
  121. X    ULONG numblocks;        /* Number of blocks on this disk        */
  122. X    ULONG reserved;            /* Number of blocks reserved at start    */
  123. X                            /* (included in numblocks count)        */
  124. X} DISKDEV;
  125. X
  126. X/*
  127. X *        Global variables
  128. X *        ----------------
  129. X */
  130. X
  131. XBPTR    filehandle;                /* Filehandle used when creating dummy file    */
  132. XBPTR    lock;                    /* Lock on dummy file used to store tracks    */
  133. XLONG    filekey;                /* AmigaDOS block of dummy file header        */
  134. Xchar    *pathname;                /* Full AmigaDOS path of file to create        */
  135. Xchar    devname[300];            /* AmigaDOS device we are operating on        */
  136. XDISKDEV    diskdev[1];                /* Description of disk device we are using    */
  137. Xstruct    IOStdReq *req;            /* Standard request for source device        */
  138. XMSGPORT    *reqport;                /* Message port for replies from disk dev.    */
  139. XMSGPORT    *diskport;                /* Message port of process of disk device     */
  140. Xint        devopen;                /* True if disk exec device is open            */
  141. Xint        inhibited;                /* True if destination device is inhibited    */
  142. Xvoid     *readbuf;                /* Buffer to read a single disk block into    */
  143. Xvoid    *writebuf;                /* Buffer to write a single disk block from    */
  144. XULONG    *bitmap;                /* Array of longwords holding bitmap        */
  145. XULONG    *bitmapblocks;            /* Array of block numbers for disk bitmap    */
  146. XULONG    bitmapsize;                /* Size of bitmap in bytes                    */
  147. XULONG    bitmapblocksize;        /* Size of bitmap blocks array in bytes        */
  148. XULONG    numbitmapblocks;        /* Number of blocks storing bitmap on disk    */
  149. Xstruct  FileHeaderBlock *headers;    /* Array of file headers/extensions        */
  150. Xstruct    DataBlock        *datablock;    /* Datablock used if accessing OFS        */
  151. Xstruct    RootBlock         *rootblock;    /* Rootblock of current disk            */
  152. XULONG    headersize;                /* Size of array of file headers in bytes    */
  153. XULONG    datasize;                /* Size of datablock in bytes                */
  154. XULONG    rootsize;                /* Size of rootblock in bytes                */
  155. XULONG    datablocknum;            /* Block # to store front data block at        */
  156. X
  157. X
  158. X/*
  159. X *        print()
  160. X *        -------
  161. X *        Outputs a message to stdout
  162. X */
  163. Xvoid print(char *s)
  164. X{
  165. X    Write(Output(), s, strlen(s));
  166. X}
  167. X#define print2(s1,s2)    (print(s1),print(s2))
  168. X#define print3(s1,s2,s3) (print(s1),print(s2),print(s3))
  169. X
  170. X/*
  171. X *        numtostr()
  172. X *        ----------
  173. X *        Simple little function which returns a pointer to a static string
  174. X *        representation of the passed in number.
  175. X */
  176. Xchar *numtostr(int n)
  177. X{
  178. X    static char s[20];
  179. X    int i = 19;
  180. X
  181. X    s[19] = '\0';
  182. X    if (n)
  183. X        while (n) {
  184. X            s[--i] = '0' + (n % 10);
  185. X            n /= 10;
  186. X        }
  187. X    else
  188. X        s[--i] = '0';
  189. X    return(&s[i]);
  190. X}
  191. X
  192. X
  193. X/*
  194. X *        cleanup()
  195. X *        ---------
  196. X *        Closes all opened resources, and exits with specified error code.
  197. X */
  198. Xvoid cleanup(int code)
  199. X{
  200. X    if (devopen) {
  201. X        if (diskdev->isfloppy) {    /* Turn off drive motor if floppy disk */
  202. X            req->io_Command = TD_MOTOR;
  203. X            req->io_Length = 0;
  204. X            DoIO(req);
  205. X        }
  206. X        CloseDevice((IOREQ *)req);
  207. X    }
  208. X    if (inhibited)
  209. X        inhibit(diskport, FALSE);
  210. X    if (readbuf)
  211. X        FreeMem(readbuf, diskdev->blocksize);
  212. X    if (writebuf)
  213. X        FreeMem(writebuf, diskdev->blocksize);
  214. X    if (req)
  215. X        DeleteStdIO(req);
  216. X    if (reqport)
  217. X        DeletePort(reqport);
  218. X    if (lock)
  219. X        UnLock(lock);
  220. X    if (filehandle)
  221. X        Close(filehandle);
  222. X    if (bitmap)
  223. X        FreeMem(bitmap, bitmapsize);
  224. X    if (bitmapblocks)
  225. X        FreeMem(bitmapblocks, bitmapblocksize);
  226. X    if (headers)
  227. X        FreeMem(headers, headersize);
  228. X    if (datablock)
  229. X        FreeMem(datablock, datasize);
  230. X    if (rootblock)
  231. X        FreeMem(rootblock, rootsize);
  232. X    exit(code);
  233. X}
  234. X
  235. X
  236. X/*
  237. X *        chkabort()
  238. X *        ----------
  239. X *        A replacement for Lattice's chkabort(), which doesn't carry all
  240. X *        the extra baggage. If CTRL-C is detected, this function never
  241. X *        returns but instead calls cleanup. Since Lattice's exit() code
  242. X *        may call chkabort(), a check is made to ensure that cleanup()
  243. X *        only gets called once, otherwise there would be a problem if the
  244. X *        user pressed Ctrl-C twice in quick succession.
  245. X */
  246. Xvoid chkabort(void)
  247. X{
  248. X    static int gotctrlc = FALSE;
  249. X    if (!gotctrlc && (SetSignal(0,0) & SIGBREAKF_CTRL_C)) {
  250. X        gotctrlc = TRUE;
  251. X        print("^C\n");
  252. X        cleanup(10);
  253. X    }
  254. X}
  255. X
  256. X
  257. X/*
  258. X *        GetVolume()
  259. X *        -----------
  260. X *        This function searches the device list looking for a physical device
  261. X *        that currently contains the specified disk volume. When it finds it,
  262. X *        it fills in the DISKDEV structure with information about the physical
  263. X *        device which can then be used to access it at the block level.
  264. X */
  265. Xint GetVolume(char *devname, DISKDEV *dev)
  266. X{
  267. X    struct RootNode *rootnode;
  268. X    struct DosInfo *dosinfo;
  269. X    struct DeviceNode *devnode;
  270. X    struct FileSysStartupMsg *startup;
  271. X    struct DosEnvec *dosenvec;
  272. X    unsigned char *p;
  273. X    int namelen = strlen(devname);
  274. X
  275. X    if (LASTCHAR(devname) != ':')    /* Device names must end with ':' */
  276. X        return (FALSE);
  277. X    /*
  278. X     *        First of all, find the device
  279. X     */
  280. X    rootnode = (struct RootNode *)DOSBase->dl_Root;
  281. X    dosinfo = (struct DosInfo *)BADDR(rootnode->rn_Info);
  282. X    devnode = (struct DeviceNode *)BADDR(dosinfo->di_DevInfo);
  283. X
  284. X    Forbid();    /* Make sure list doesn't change while we scan it */
  285. X
  286. X    while (devnode != NULL) {
  287. X        p = (unsigned char *)BADDR(devnode->dn_Name)+1;
  288. X        if (!strnicmp(devname, p, namelen-1)) {    /* Don't compare the ':' */
  289. X            /*
  290. X             *        Matched name successfully. Now check if it's a device.
  291. X             *        Note that we carry on searching if it's not a device
  292. X             *        (rather than returning FALSE immediately) since there
  293. X             *        may be a volume called RAD: as well as a device called
  294. X             *        RAD:, for example.
  295. X             */
  296. X            if (devnode->dn_Type == DLT_DEVICE) {
  297. X                if (devnode->dn_Startup < 20)    /* Is there a startup bit?    */
  298. X                    goto notfound;                /* If not, not disk device    */
  299. X                    /* Eek! A GOTO! */
  300. X
  301. X                startup = (struct FileSysStartupMsg *)
  302. X                                        BADDR(devnode->dn_Startup);
  303. X
  304. X                if (dev) {
  305. X                    dev->devname = ((char *)BADDR(startup->fssm_Device))+1;
  306. X                    dev->isfloppy = (!strcmp(TD_NAME, dev->devname));
  307. X                    dev->unit = startup->fssm_Unit;
  308. X                }
  309. X
  310. X                if (startup->fssm_Environ < 20)
  311. X                    goto notfound;
  312. X                /* Another GOTO! The world will end in 5 seconds... */
  313. X
  314. X                dosenvec = (struct DosEnvec *)BADDR(startup->fssm_Environ);
  315. X
  316. X                if (dev) {
  317. X                    dev->isffs            = dosenvec->de_DosType == 0x444F5301;
  318. X                    /*
  319. X                     *        Since dosenvec->de_DosType does NOT equal
  320. X                     *        0x444F5300 for standard OFS AmigaDOS disks,
  321. X                     *        I can't check it to see if the filing system
  322. X                     *        is "known". Hence, for now, just assume its
  323. X                     *        always known (since it can currently only be
  324. X                     *        OFS or FFS, and I can't think of any other way
  325. X                     *        of checking).
  326. X                     */
  327. X                    dev->isknown        = 1;
  328. X                    dev->blocksize        = dosenvec->de_SizeBlock << 2;
  329. X                    dev->blockspertrack    = dosenvec->de_BlocksPerTrack;
  330. X                    dev->surfaces        = dosenvec->de_Surfaces;
  331. X                    dev->lowcyl            = dosenvec->de_LowCyl;
  332. X                    dev->numcyl            = (dosenvec->de_HighCyl -
  333. X                                                dosenvec->de_LowCyl) + 1;
  334. X                    dev->numblocks = dev->blockspertrack * dev->surfaces
  335. X                                                          * dev->numcyl;
  336. X                    dev->reserved = dosenvec->de_Reserved;
  337. X                }
  338. X                Permit();
  339. X                return (TRUE);
  340. X            }
  341. X        }
  342. X        devnode = (struct DeviceNode *)BADDR(devnode->dn_Next);
  343. X    }
  344. Xnotfound:
  345. X    Permit();
  346. X    return (FALSE);
  347. X}
  348. X
  349. X/*
  350. X *        help()
  351. X *        ------
  352. X *        Prints out a help message about trackfile
  353. X */
  354. Xvoid help(void)
  355. X{
  356. X    print3(
  357. X"Trackfile (C) Copyright Eddy Carroll, January 1990. Freely distributable.\n",
  358. X"Creates an AmigaDos file which reserves specified tracks on a disk.\n\n",
  359. X"Usage: tfile <pathname> <start> <end>\n\n"); print3(
  360. X"  <pathname>  The full AmigaDOS path of the dummy file that will be \
  361. Xcreated\n",
  362. X"              to hold the reserved tracks, to stop AmigaDOS using them.\n\n",
  363. X"  <start>     The starting track to be reserved on the disk.\n\n" ); print(
  364. X"  <end>       The ending track to be reserved on the disk.\n\n" );
  365. X}
  366. X
  367. X
  368. X/*
  369. X *        opendev()
  370. X *        ---------
  371. X *        Opens the disk device, allocates stdreqs etc. Two buffers are
  372. X *        also allocated, one for reading a single block and one for
  373. X *        writing a single block.
  374. X */
  375. Xvoid opendev(void)
  376. X{
  377. X    ULONG memflags = MEMF_PUBLIC;
  378. X
  379. X    if (diskdev->isfloppy)
  380. X        memflags |= MEMF_CHIP;
  381. X
  382. X    reqport = (MSGPORT *)CreatePort(0,0);
  383. X    if (!reqport) {
  384. X        print("Couldn't allocate message port\n");
  385. X        cleanup(10);
  386. X    }
  387. X
  388. X    readbuf = AllocMem(diskdev->blocksize, memflags);
  389. X    if (!readbuf) {
  390. X        print("Couldn't allocate memory for read buffer\n");
  391. X        cleanup(10);
  392. X    }
  393. X
  394. X    writebuf = AllocMem(diskdev->blocksize, memflags);
  395. X    if (!writebuf) {
  396. X        print("Couldn't allocate memory for write buffer\n");
  397. X        cleanup(10);
  398. X    }
  399. X
  400. X    req = CreateStdIO(reqport);
  401. X    if (!req) {
  402. X        print("Couldn't allocate IO request - memory is low!\n");
  403. X        cleanup(10);
  404. X    }
  405. X
  406. X    if (OpenDevice(diskdev->devname, diskdev->unit, (IOREQ *)req, 0L)) {
  407. X        print3("Can't open device ", diskdev->devname, "\n");
  408. X        cleanup(10);
  409. X    }
  410. X    devopen = TRUE;
  411. X}
  412. X
  413. X/*
  414. X *        readblock()   &   writeblock()
  415. X *        -----------       ------------
  416. X *
  417. X *        These two functions read or write a block from the disk.
  418. X *        See the definition of transferblocks() below for more information.
  419. X */
  420. X#define BLOCK_READ        0
  421. X#define BLOCK_WRITE        1
  422. X
  423. X#define readblock(buffer, s)  transferblocks(buffer, s, 1, BLOCK_READ)
  424. X#define writeblock(buffer, s) transferblocks(buffer, s, 1, BLOCK_WRITE)
  425. X
  426. X/*
  427. X *        transferblocks()
  428. X *        ----------------
  429. X *        Transfers n blocks to/from the disk into the buffer indicated,
  430. X *        starting at block s. Note that if you are using a floppy drive, the
  431. X *        buffer MUST be allocated in CHIP ram! You can ensure this by
  432. X *        including MEMF_CHIP in the flags to AllocMem() if diskdev->isfloppy
  433. X *        is true. Zero is returned if an error occurred, else non-zero.
  434. X *        Up to three retries are done before failure is accepted.
  435. X *
  436. X *        The direction of transfer is BLOCK_READ to read blocks in, or
  437. X *        BLOCK_WRITE to write blocks out.
  438. X */
  439. Xint transferblocks(void *buffer, int s, int n, int direction)
  440. X{
  441. X    int retry, parstart;
  442. X
  443. X    /*
  444. X     *        Because AmigaDOS works with partitions, Block 0 of an AmigaDOS
  445. X     *        device may in fact be block 12345 of an exec device, depending
  446. X     *        where the partition starts. Hence, before trying to access an
  447. X     *        Amiga-DOS numbered block, we need to add in the block at which
  448. X     *        the current partition starts.
  449. X     */
  450. X    parstart = diskdev->lowcyl * diskdev->blockspertrack * diskdev->surfaces;
  451. X
  452. X    /*
  453. X     *        Now read in blocks from disk
  454. X     */
  455. X    for (retry = 0; retry < 3; retry++) {
  456. X        if (direction == BLOCK_READ)
  457. X            req->io_Command = CMD_READ;
  458. X        else
  459. X            req->io_Command = CMD_WRITE;
  460. X        req->io_Length  = diskdev->blocksize * n;
  461. X        req->io_Offset  = diskdev->blocksize * (s + parstart);
  462. X        req->io_Data    = buffer;
  463. X        if (!DoIO((IOREQ *)req))
  464. X            break;        /* Succeeded, so break out of loop */
  465. X    }
  466. X    if (retry == 3)
  467. X        return (0);
  468. X    else
  469. X        return (1);
  470. X}
  471. X
  472. X/*
  473. X *        SendPacket()
  474. X *        ------------
  475. X *        ``Sort of'' simulates the ARP SendPacket() routine which sends
  476. X *        a packet to AmigaDos, and gets a reply if appropriate. What is
  477. X *        passed in is the action to be executed (one of the ACTION_xxx
  478. X *        definitions in dosextens.h), a pointer to a longword array of 7
  479. X *        arguments to be passed to the device, and the msgport of the device
  480. X *        as returned by DeviceProc("DF0:") for example. If result is non-NULL
  481. X *        then it should be a pointer to a two element array of ULONGs, and it
  482. X *        fills in the 0th element with the primary result, and the the
  483. X *        1st element with the secondary result.
  484. X */
  485. Xint SendPacket(ULONG action, void *args, MSGPORT *devport, ULONG *result)
  486. X{
  487. X    PROC *proc = (PROC *)FindTask(NULL);
  488. X    STDPKT *packet;
  489. X
  490. X    packet = (STDPKT *)AllocMem(sizeof(STDPKT), MEMF_CLEAR | MEMF_PUBLIC);
  491. X    if (!packet)
  492. X        return (FALSE);
  493. X    packet->sp_Msg.mn_Node.ln_Name = (char *)&packet->sp_Pkt;
  494. X    packet->sp_Pkt.dp_Link         = &packet->sp_Msg;
  495. X    packet->sp_Pkt.dp_Port         = &proc->pr_MsgPort;
  496. X    packet->sp_Pkt.dp_Type         = action;
  497. X    memcpy(&packet->sp_Pkt.dp_Arg1, args, sizeof(ULONG) * 7);
  498. X
  499. X    /*
  500. X     *        Okay, we've done the necessary magic to create an AmigaDos
  501. X     *        packet lookalike (thanks to Matt Dillon in Transactor V1.1).
  502. X     *        Now we send the message to the Dos process, and get the reply.
  503. X     *        Then our message will be filled in with the response from the
  504. X     *        Dos process.
  505. X     */
  506. X    PutMsg(devport, (struct Message *)packet);
  507. X    WaitPort(&proc->pr_MsgPort);
  508. X    GetMsg(&proc->pr_MsgPort);
  509. X    if (result) {
  510. X        result[0] = packet->sp_Pkt.dp_Res1;
  511. X        result[1] = packet->sp_Pkt.dp_Res2;
  512. X    }
  513. X    FreeMem(packet, sizeof(STDPKT));
  514. X    return (TRUE);
  515. X}
  516. X
  517. X
  518. X/*
  519. X *        inhibit()
  520. X *        ---------
  521. X *        This function inhibits (if mode is TRUE) or uninhibits (if mode is
  522. X *        FALSE) the specified device.
  523. X */
  524. Xvoid inhibit(MSGPORT *devport, int mode)
  525. X{
  526. X    ULONG pktargs[7];
  527. X    int i;
  528. X
  529. X    pktargs[0] = mode;            /* Select inhibit or opposite */
  530. X    for (i = 1; i < 7; i++)        /* Clear other arguments      */
  531. X        pktargs[i] = 0;
  532. X
  533. X    if (!SendPacket(ACTION_INHIBIT, pktargs, devport, NULL)) {
  534. X        print("Couldn't send inhibit packet to device\n");
  535. X        cleanup(10);
  536. X    }
  537. X}
  538. X
  539. X
  540. X/*
  541. X *        flushdisk()
  542. X *        -----------
  543. X *        This function flushes the specified DOS device, ensuring that all
  544. X *        dirty buffers are written to disk and the bitmap is up to date.
  545. X */
  546. Xvoid flushdisk(MSGPORT *devport)
  547. X{
  548. X    ULONG pktargs[7];
  549. X    int i;
  550. X
  551. X    for (i = 0; i < 7; i++)        /* Clear arguments */
  552. X        pktargs[i] = 0;
  553. X
  554. X    if (!SendPacket(ACTION_FLUSH, pktargs, devport, NULL)) {
  555. X        print("Couldn't send flush packet to device\n");
  556. X        cleanup(10);
  557. X    }
  558. X}
  559. X
  560. X/*
  561. X *        fixchecksum()
  562. X *        -------------
  563. X *        Calculates the checksum for the specified block, and stores it
  564. X *        in the indicated place, which will usually be a pointer into the
  565. X *        block itself. The block is assumed to be 512 bytes long.
  566. X */
  567. Xvoid fixchecksum(void *block, ULONG *checksum)
  568. X{
  569. X    ULONG *blk = block, *start, *end;
  570. X    ULONG sum = 0;
  571. X
  572. X    end = blk + 128;
  573. X    *checksum = 0;            /* Clear checksum so it won't affect count */
  574. X
  575. X    for (start = blk; start < end; start++)
  576. X        sum += *start;
  577. X
  578. X    *checksum = -sum;        /* Real checksum is complement of total */
  579. X}
  580. X
  581. X/*
  582. X *        readrootblock()
  583. X *        ---------------
  584. X *        This function simply reads in the root block of the disk into
  585. X *        the global 'root' structure for the rest of the program to access.
  586. X */
  587. Xvoid readrootblock(void)
  588. X{
  589. X    ULONG rootblocknum = diskdev->numblocks / 2;
  590. X    ULONG memflags = MEMF_PUBLIC;
  591. X
  592. X    if (diskdev->isfloppy)
  593. X        memflags |= MEMF_CHIP;
  594. X
  595. X    rootsize  = 512;
  596. X    rootblock = AllocMem(rootsize, memflags);
  597. X    if (!rootblock) {
  598. X        print("Out of memory allocating space for root block\n");
  599. X        cleanup(10);
  600. X    }
  601. X    if (!readblock(rootblock, rootblocknum)) {
  602. X        print("Error reading root block from disk\n");
  603. X        cleanup(10);
  604. X    }
  605. X}
  606. X
  607. X
  608. X#ifdef DEBUG
  609. X/*
  610. X *        writerootblock()
  611. X *        ----------------
  612. X *        This function writes the rootblock back to disk.
  613. X *        Temporarily, it zaps the "validated" flag to force a validation
  614. X *        to occur.
  615. X */
  616. Xvoid writerootblock(void)
  617. X{
  618. X    ULONG rootblocknum = diskdev->numblocks / 2;
  619. X
  620. X    rootblock->BitmapFlag = 0;
  621. X    fixchecksum(rootblock, &rootblock->Checksum);
  622. X    writeblock(rootblock, rootblocknum);
  623. X}
  624. X
  625. X#endif
  626. X
  627. X
  628. X/*
  629. X *        readbitmap()
  630. X *        ------------
  631. X *
  632. X *        This function creates a memory copy of the disks's bitmap, by
  633. X *        reading in all the disk's bitmap blocks. Two arrays are created;
  634. X *        The first holds the bitmap data itself, the second is a longword
  635. X *        array holding the block numbers that the bitmap is stored on, for
  636. X *        use when it is being written out again.
  637. X *
  638. X *        If an error occurs, the function prints a message and exits to dos.
  639. X *        It is assumed that the root block has been read in to 'root' before
  640. X *        calling this function.
  641. X */
  642. Xvoid readbitmap(void)
  643. X{
  644. X    int i, end;
  645. X    ULONG nextblock;
  646. X    ULONG *block = readbuf;
  647. X
  648. X    /*
  649. X     *        First let's calculate the size of each array. The size of the
  650. X     *        bitmap array is simply the number of blocks on the disk divided
  651. X     *        by 8 (since a single byte can represent 8 blocks). The size of
  652. X     *        the array to hold the locations of the bitmap blocks is the
  653. X     *        number of blocks divided by 4064, since each bitmap block
  654. X     *        can represent 4064 disk blocks (with 32 bits left over for
  655. X     *        the block checksum).
  656. X     */
  657. X
  658. X    /*
  659. X     *        To calculate the number of DOS-usable blocks on the disk, we need
  660. X     *        to subtract the number of blocks reserved at the start of the
  661. X     *        partition. In addition, we add on 4063 so that the result after
  662. X     *        division will be rounded up to the next integral block number.
  663. X     */
  664. X    numbitmapblocks = (diskdev->numblocks + 4063 - diskdev->reserved) / 4064;
  665. X    bitmapsize        = numbitmapblocks * 508;   /* 4 bytes used for checksum */
  666. X    bitmapblocksize    = numbitmapblocks * 4;
  667. X
  668. X    /*
  669. X     *        Now, allocate the arrays
  670. X     */
  671. X    bitmap = AllocMem(bitmapsize, 0L);
  672. X    if (!bitmap) {
  673. X        print("Can't allocate memory to store disk bitmap.\n");
  674. X        cleanup(10);
  675. X    }
  676. X    bitmapblocks = AllocMem(bitmapblocksize, 0L);
  677. X    if (!bitmapblocks) {
  678. X        print("Can't allocate memory to store disk bitmap sector numbers.\n");
  679. X        cleanup(10);
  680. X    }
  681. X
  682. X    /*
  683. X     *        Now, read in all the sector numbers from the root block
  684. X     */
  685. X    end = MIN(numbitmapblocks, 25);
  686. X    for (i = 0; i < end; i++)
  687. X        bitmapblocks[i] = rootblock->BitmapKeys[i];
  688. X
  689. X    /*
  690. X     *        If we are using a large disk partition (larger than 52 Megs or so)
  691. X     *        we also need to read in the bitmap extension block(s). Each
  692. X     *        extension block contains 127 sector numbers.
  693. X     *
  694. X     *        Note: Since I am unsure of the extension bitmap format used,
  695. X     *        this code is being commented out for now, and a check has been
  696. X     *        included in main() to ensure no disk big enough to have an
  697. X     *        bitmap extension is allowed to get here; when I find out the
  698. X     *        format, it will be trivial to add support for it here, since the
  699. X     *        rest of the program just deals with an array of bitmap sector
  700. X     *        numbers (and the bitmap array itself of course).
  701. X     *
  702. X     *        For the code, I'm assuming the bitmap is stored back to front
  703. X     *        (i.e. first sector last), based on Betty Clay's article in
  704. X     *        Transactor. I want to verify this first though before letting
  705. X     *        it loose on the unsuspecting public (after all, a bug that screws
  706. X     *        up a 50 Mb disk is not going to go down well with people who
  707. X     *        have 50 Mb disks... :-)
  708. X     */
  709. X
  710. X    nextblock = rootblock->BitmapExtend;
  711. X
  712. X#ifdef FOUND_OUT_HOW_THE_BITMAP_IS_STORED
  713. X
  714. X    while (i < numbitmapblocks) {
  715. X        int p = 127;
  716. X
  717. X        if (!readblock(block, nextblock)) {
  718. X            print("Error reading bitmap extension block from disk\n");
  719. X            cleanup(10);
  720. X        }
  721. X        nextblock = block[0];
  722. X        end    = MIN(i + 127, numbitmapblocks);
  723. X        while (i < end)
  724. X            bitmapblocks[i++] = blocks[p--];
  725. X    }
  726. X
  727. X#endif
  728. X
  729. X    /*
  730. X     *        Now I know what sectors the bitmap itself is stored on, so
  731. X     *        I can read it in to memory.
  732. X     */
  733. X    for (i = 0; i < numbitmapblocks; i++) {
  734. X        if (!readblock(block, bitmapblocks[i])) {
  735. X            print("Error reading in bitmap from disk\n");
  736. X            cleanup(10);
  737. X        }
  738. X        /*
  739. X         *        Remember, bitmap is pointer to ULONG so we use longword
  740. X         *        offsets when copying the bitmap data into the bitmap array.
  741. X         */
  742. X        memcpy(bitmap + (127 * i), block + 1, 508);
  743. X    }
  744. X}
  745. X
  746. X/*
  747. X *        writebitmap()
  748. X *        -------------
  749. X *        Writes the disk bitmap back to disk, storing it on the sectors
  750. X *        it was read in from earlier.
  751. X */
  752. Xvoid writebitmap(void)
  753. X{
  754. X    ULONG *diskblock = (ULONG *)writebuf;
  755. X    int i;
  756. X
  757. X    for (i = 0; i < numbitmapblocks; i++) {
  758. X        /*
  759. X         *        For each bitmap block, copy the 127 longwords into write
  760. X         *        buffer, correct checksum, then write to disk.
  761. X         */
  762. X        memcpy(diskblock + 1, bitmap + (i * 127), 508);
  763. X        fixchecksum(diskblock, &diskblock[0]);
  764. X        if (!writeblock(diskblock, bitmapblocks[i])) {
  765. X            print(
  766. X"Error writing updated bitmap to disk! Copy important files to a new disk!\n");
  767. X            cleanup(10);
  768. X        }
  769. X    }
  770. X}
  771. X
  772. X#ifdef DEBUG
  773. X/*
  774. X *        dumpbitmap()
  775. X *        ------------
  776. X *        A quick hack function to display the bitmap on screen, to allow
  777. X *        visual confirmation that it was read in correctly, altered
  778. X *        properly etc.
  779. X */
  780. Xvoid dumpbitmap(void)
  781. X{
  782. X    int t, s, c, blocknum, i;
  783. X    static char buf[300];
  784. X
  785. X    for (c = 0; c < diskdev->numcyl; c++) {
  786. X        for (t = 0; t < diskdev->surfaces; t++) {
  787. X
  788. X            blocknum = (((c * diskdev->surfaces) + t)
  789. X                        * diskdev->blockspertrack);
  790. X            chkabort();
  791. X            print3(numtostr(c),",",numtostr(t));
  792. X            print3(": ",numtostr(blocknum),";  ");
  793. X            i = 0;
  794. X            for (s = 0; s < diskdev->blockspertrack; s++) {
  795. X                blocknum = (((c * diskdev->surfaces) + t)
  796. X                            * diskdev->blockspertrack) + s;
  797. X                if (blocknum < diskdev->reserved ||
  798. X                        blocknum >= diskdev->numblocks)
  799. X                    buf[i++] = 'O';    /* Block reserved */
  800. X                else {
  801. X                    blocknum = blocknum - diskdev->reserved;
  802. X                    if (bitmap[blocknum >> 5] & (1 << (blocknum & 31)))
  803. X                        buf[i++] = '-';    /* Block unused */
  804. X                    else
  805. X                        buf[i++] = 'O';    /* Block in use    */
  806. X                }
  807. X            }
  808. X            buf[i] = '\0';
  809. X            print2(buf, "\n");
  810. X        }
  811. X    }
  812. X}
  813. X#endif
  814. X
  815. X/*
  816. X *        filltracks()
  817. X *        ------------
  818. X *        Tries to mark the specified cylinders as used in the memory copy
  819. X *        of the disk bitmap. 1 is returned if successful, 0 if any of the
  820. X *        blocks in the cylinders were already in use.
  821. X */
  822. Xint filltracks(int lowcyl, int highcyl)
  823. X{
  824. X    long startblock, endblock;                /* Adjusted block numbers        */
  825. X    long startblockindex, endblockindex;    /* Indexes into bitmap array    */
  826. X    long startoffset, endoffset;            /* Bit offsets into bitmap word    */
  827. X    long lastblock;                            /* Last bitmap block on disk    */
  828. X    int i, warn = 0;
  829. X
  830. X    lastblock = diskdev->numblocks - diskdev->reserved;
  831. X
  832. X    startblock = lowcyl * diskdev->surfaces * diskdev->blockspertrack
  833. X                        - diskdev->reserved;
  834. X    if (startblock < 0) {
  835. X        warn = 1;
  836. X        startblock = 0;
  837. X    }
  838. X    if (startblock >= lastblock) {
  839. X        warn = 1;
  840. X        startblock = lastblock;
  841. X    }
  842. X    startblockindex = startblock >> 5;
  843. X    startoffset        = startblock & 31;
  844. X
  845. X    endblock   = (highcyl + 1) * diskdev->surfaces * diskdev->blockspertrack
  846. X                         - diskdev->reserved;
  847. X    if (endblock < 0) {
  848. X        warn = 1;
  849. X        endblock = 0;
  850. X    }
  851. X    if (endblock > lastblock) {
  852. X        warn = 1;
  853. X        endblock = lastblock;
  854. X    }
  855. X    endblockindex = endblock   >> 5;
  856. X    endoffset      = endblock   & 31;
  857. X
  858. X    if (warn)
  859. X        print("(Warning: Track range includes reserved portion of disk.)\n");
  860. X    
  861. X    if (startblockindex == endblockindex) {
  862. X        /*
  863. X         *        Start and stop in same bitmap word, so set the bits manually
  864. X         */
  865. X        for (i = startoffset; i < endoffset; i++) {
  866. X            if ((bitmap[startblockindex] & (1 << i)) == 0)
  867. X                return (0);                        /* Block already in use */
  868. X            else
  869. X                bitmap[startblockindex] &= ~(1 << i); /* Clear bit in bitmap */
  870. X        }
  871. X        return (1);
  872. X    }
  873. X
  874. X    /*
  875. X     *        Allocate first few blocks a bit at a time up to end of longword
  876. X     */
  877. X    for (i = startoffset; i < 32; i++) {
  878. X        if ((bitmap[startblockindex] & (1 << i)) == 0)
  879. X            return (0);                            /* Block already in use */
  880. X        else
  881. X            bitmap[startblockindex] &= ~(1 << i);    /* Clear bit in bitmap    */
  882. X    }
  883. X
  884. X    /*
  885. X     *        Now allocate inbetween blocks a longword at a time for speed
  886. X     */
  887. X    for (i = startblockindex + 1; i < endblockindex; i++) {
  888. X        if (bitmap[i] != 0xffffffff)
  889. X            return (0);                            /* Block already in use    */
  890. X        else
  891. X            bitmap[i] = 0;                        /* Set all blocks used    */
  892. X    }
  893. X
  894. X    /*
  895. X     *        Finally, allocate last few blocks a bit at a time
  896. X     */
  897. X    for (i = 0; i < endoffset; i++) {
  898. X        if ((bitmap[endblockindex] & (1 << i)) == 0)
  899. X            return (0);                            /* Block already in use */
  900. X        else
  901. X            bitmap[endblockindex] &= ~(1 << i);        /* Clear bit in bitmap    */
  902. X    }
  903. X    return (1);
  904. X}
  905. X
  906. X/*
  907. X *        allocblock()
  908. X *        ------------
  909. X *        Tries to allocate a block as close to block `key' as possible,
  910. X *        from the remaining free blocks in the disk bitmap. The allocation
  911. X *        algorithm is as follows:
  912. X *
  913. X *            - Find the nearest free block before the key
  914. X *            - Find the nearest free block after the key
  915. X *            - Allocate whichever one is closest
  916. X *
  917. X *        If the allocation was successful, the number of the new block is
  918. X *        stored in newkey.
  919. X */
  920. Xint allocblock(ULONG key, ULONG *newkey)
  921. X{
  922. X    ULONG curblock  = key - diskdev->reserved;
  923. X    ULONG endblock  = diskdev->numblocks - diskdev->reserved;
  924. X    ULONG endindex  = endblock >> 5;
  925. X    ULONG useblock;
  926. X    long  i, j, tp;                        /* Must be signed */
  927. X    long  curindex  = curblock >> 5;
  928. X    long  curoffset = curblock & 31;
  929. X    int   backblock = -1, forblock = -1;
  930. X
  931. X    /*
  932. X     *        Find nearest block before current key. Remember that in the
  933. X     *        bitmap, a `1' means the block is free, a `0' means its allocated.
  934. X     *
  935. X     *        First of all, search back within current bitmap word
  936. X     */
  937. X    tp = bitmap[curindex];
  938. X    for (i = curoffset; i >= 0; i--) {
  939. X        if (tp & (1 << i)) {
  940. X            backblock = (curindex << 5) + i;
  941. X            break;
  942. X        }
  943. X    }
  944. X
  945. X    if (backblock < 0) {
  946. X        /*
  947. X         *        Didn't find room in initial word, so carry on search
  948. X         */
  949. X        for (i = curindex - 1; i >= 0; i--) {
  950. X            if (bitmap[i] != 0) {
  951. X                tp = bitmap[i];
  952. X                /*
  953. X                 *        Found free block word; now find what bit it is;
  954. X                 *        Note that because of the way we entered this
  955. X                 *        loop (with tp != 0), termination of the next
  956. X                 *        loop is guaranteed.
  957. X                 */
  958. X                for (j = 31; (tp & (1 << j)) == 0; j--)
  959. X                    ;
  960. X                backblock = (i << 5) + j;
  961. X                break;
  962. X            }
  963. X        }
  964. X    }
  965. X
  966. X    /*
  967. X     *        Now find nearest block after current key
  968. X     */
  969. X    tp = bitmap[curindex];
  970. X    for (i = curoffset; i < 32; i++) {
  971. X        if (tp & (1 << i)) {
  972. X            forblock = (curindex << 5) + i;
  973. X            break;
  974. X        }
  975. X    }
  976. X
  977. X    if (forblock < 0) {
  978. X        /*
  979. X         *        Didn't find room in initial word, so carry on search
  980. X         */
  981. X        for (i = curindex + 1; i <= endindex; i--) {
  982. X            if (bitmap[i] != 0) {
  983. X                tp = bitmap[i];
  984. X                /*
  985. X                 *        Found free room; now find what bit it is;
  986. X                 *        Note that because of the way we entered this
  987. X                 *        loop (with tp != 0), termination of the next
  988. X                 *        loop is guaranteed.
  989. X                 */
  990. X                for (j = 0; (tp & (1 << j)) == 0; j++)
  991. X                    ;
  992. X                forblock = (i << 5) + j;
  993. X                break;
  994. X            }
  995. X        }
  996. X    }
  997. X
  998. X    /*
  999. X     *        Now, forblock and backblock hold block numbers which are free
  1000. X     *        in the bitmap (or -1 if none was found). We just have to
  1001. X     *        work out which one to use.
  1002. X     */
  1003. X    if (forblock < 0) {
  1004. X        if (backblock < 0)
  1005. X            return (0);
  1006. X        else
  1007. X            useblock = backblock;    
  1008. X    } else {
  1009. X        if (backblock < 0)
  1010. X            useblock = forblock;
  1011. X        else {
  1012. X            if ((key - backblock) < (forblock - key))
  1013. X                useblock = backblock;
  1014. X            else
  1015. X                useblock = forblock;
  1016. X        }
  1017. X    }
  1018. X
  1019. X    /*
  1020. X     *        At this stage, useblock is the block number to allocate and
  1021. X     *        return.
  1022. X     */
  1023. X    bitmap[useblock >> 5] &= ~(1 << (useblock & 31));
  1024. X    *newkey = useblock + diskdev->reserved;
  1025. X    /*
  1026. X     *        Finally, a brief sanity check to ensure the number is in range
  1027. X     *        It SHOULD be but it doesn't do any harm to check, in case we
  1028. X     *        ran off the end of the bitmap or something...
  1029. X     */
  1030. X    if (*newkey < diskdev->numblocks)
  1031. X        return (1);
  1032. X    else
  1033. X        return (0);
  1034. X}
  1035. X
  1036. X
  1037. X/*
  1038. X *        createfileheaders()
  1039. X *        -------------------
  1040. X *        Allocates an array of file headers and extension blocks, and
  1041. X *        fills them in with the appropriate values to make AmigaDOS think
  1042. X *        a file exists on the tracks the user indictated. The key is
  1043. X *        the block number of the file header which is to be modified to
  1044. X *        hold the dummy file.
  1045. X *
  1046. X *        As well as allocating the blocks on the tracks to be reserved,
  1047. X *        an additional `frontend' data block is stuck at the front of the
  1048. X *        file containing a brief message. This stops DOS from getting
  1049. X *        confused if the user tries to access the file. Under the FFS it
  1050. X *        isn't needed, but under the OFS, a series crash results. To stop
  1051. X *        the code getting overly complicated, the FFS gets it too.
  1052. X *
  1053. X *        After the headers have been initialised, they are written back to
  1054. X *        the disk and hey presto, a new file is born :-)
  1055. X */
  1056. Xvoid createfileheaders(int key, int lowcyl, int highcyl)
  1057. X{
  1058. X    static char msgbuf[488];
  1059. X    ULONG lastblock, startblock, endblock, numblocks, filesize;
  1060. X    ULONG curblock;
  1061. X    ULONG memflags = MEMF_PUBLIC | MEMF_CLEAR;
  1062. X    int i, j, numheaders;
  1063. X
  1064. X    lastblock = diskdev->numblocks;
  1065. X
  1066. X    startblock = lowcyl * diskdev->surfaces * diskdev->blockspertrack;
  1067. X    if (startblock < diskdev->reserved)
  1068. X        startblock = diskdev->reserved;
  1069. X
  1070. X    endblock   = (highcyl + 1) * diskdev->surfaces * diskdev->blockspertrack;
  1071. X    if (endblock > lastblock)
  1072. X        endblock = lastblock;
  1073. X
  1074. X    numblocks = 1 + endblock - startblock;    /* 1 extra for front data block */
  1075. X
  1076. X    /*
  1077. X     *        Now, we know how many blocks the file will have (we've been
  1078. X     *        careful not to count blocks which are reserved at the start
  1079. X     *        or end of the partition). Next, let's calculate how many
  1080. X     *        bytes our pretend file will have. This depends on whether
  1081. X     *        the filing system is OFS or FFS.
  1082. X     */
  1083. X    if (diskdev->isffs)
  1084. X        filesize = numblocks * 512;
  1085. X    else
  1086. X        filesize = numblocks * 488;
  1087. X
  1088. X    /*
  1089. X     *        Now allocate the file header/extensions to hold the file.
  1090. X     *        Each header/extension holds 72 block keys.
  1091. X     */
  1092. X    numheaders = (numblocks + 71) / 72;
  1093. X    headersize = numheaders * 512;
  1094. X
  1095. X    if (diskdev->isfloppy)
  1096. X        memflags |= MEMF_CHIP;
  1097. X
  1098. X    headers = AllocMem(headersize, memflags);
  1099. X    if (!headers) {
  1100. X        print("Error allocating memory for file header/extension blocks\n");
  1101. X        cleanup(10);
  1102. X    }
  1103. X    /*
  1104. X     *        Read in file header block, for file to be modified.
  1105. X     */
  1106. X    if (!readblock(headers, key)) {
  1107. X        print("Error reading file header block from disk\n");
  1108. X        cleanup(10);
  1109. X    }
  1110. X    /*
  1111. X     *        Now fill in the details for all the file extension blocks.
  1112. X     */        
  1113. X
  1114. X    curblock = startblock - 1;    /* Adjust to allow for front data block    */
  1115. X
  1116. X    for (i = 0; i < numheaders; i++) {
  1117. X        int end = MIN(72, endblock - curblock);
  1118. X
  1119. X        for (j = 0; j < end; j++)
  1120. X            headers[i].DataBlocks[71-j] = curblock++;
  1121. X    }
  1122. X
  1123. X    for (i = 1; i < numheaders; i++) {
  1124. X
  1125. X        headers[i].Type = Type_List;
  1126. X        headers[i].SecondaryType = SecType_File;
  1127. X        if (!allocblock(headers[i-1].OwnKey, &headers[i].OwnKey)) {
  1128. X            print("Not enough room on disk to store dummy file.\n");
  1129. X            cleanup(10);
  1130. X        }
  1131. X        headers[i-1].Extension    = headers[i].OwnKey;
  1132. X        headers[i].HighSeq        = 72;
  1133. X        headers[i].DataSize        = 72;
  1134. X        headers[i].Parent        = key;
  1135. X    }
  1136. X    headers[numheaders-1].Extension  = 0;
  1137. X    headers[numheaders-1].HighSeq     = numblocks % 72;
  1138. X    headers[numheaders-1].DataSize     = numblocks % 72;
  1139. X
  1140. X    headers[0].FileSize      = filesize;
  1141. X    headers[0].HighSeq    = numblocks;
  1142. X
  1143. X    /*
  1144. X     *        Now, allocate and save the dummy data block containing the
  1145. X     *        brief message. Under the FFS, users can actually access the
  1146. X     *        raw track data by seeking to (offset + 512), where offset is
  1147. X     *        the desired byte offset from the first reserved cylinder.
  1148. X     */
  1149. X    datasize  = 512;
  1150. X    datablock = AllocMem(datasize, memflags);
  1151. X    if (!datablock) {
  1152. X        print("Out of memory allocating temporary disk data block.\n");
  1153. X        cleanup(10);
  1154. X    }
  1155. X    if (!allocblock(key, &datablocknum)) {
  1156. X        print("Not enough room on disk to store dummy file.\n");
  1157. X        cleanup(10);
  1158. X    }
  1159. X    /*
  1160. X     *        Now generate message containing track data.
  1161. X     */
  1162. X    strcpy(msgbuf, FileMessage);
  1163. X    if (lowcyl == highcyl) {
  1164. X        strcat(msgbuf, "This file contains disk track ");
  1165. X        strcat(msgbuf, numtostr(lowcyl));
  1166. X    } else {
  1167. X        strcat(msgbuf, "This file contains disk tracks ");
  1168. X        strcat(msgbuf, numtostr(lowcyl));
  1169. X        strcat(msgbuf, " to ");
  1170. X        strcat(msgbuf, numtostr(highcyl));
  1171. X    }
  1172. X    strcat(msgbuf, "\n\n");
  1173. X
  1174. X    if (diskdev->isffs) {
  1175. X        /*
  1176. X         *        For FFS, just put raw data into block.
  1177. X         */
  1178. X        strcpy((char *)datablock, msgbuf);
  1179. X    } else {
  1180. X        /*
  1181. X         *        For OFS, fill in appropriate header details
  1182. X         */
  1183. X        datablock->Header    = key;
  1184. X        datablock->Type        = Type_Data;
  1185. X        datablock->SeqNum    = 1;
  1186. X        datablock->NextData    = 0;
  1187. X        datablock->DataSize = strlen(msgbuf);
  1188. X        strcpy((char *)datablock->Data, msgbuf);
  1189. X
  1190. X        fixchecksum(datablock, &datablock->Checksum);
  1191. X    }
  1192. X
  1193. X    if (!writeblock(datablock, datablocknum)) {
  1194. X        print("Error writing file data block to disk\n");
  1195. X        cleanup(10);
  1196. X    }
  1197. X
  1198. X    /*
  1199. X     *        Now fix up datablock pointers in file header
  1200. X     */
  1201. X    headers[0].FirstBlock      = datablocknum;
  1202. X    headers[0].DataBlocks[71] = datablocknum;
  1203. X
  1204. X    /*
  1205. X     *        All the data blocks have been allocated correctly; now
  1206. X     *        fix up the data checksums for each block. When the checksum
  1207. X     *        is correct, all the longwords in the block will add up to zero
  1208. X     *        (no carry when overflow occurs).
  1209. X     */
  1210. X    for (i = 0; i < numheaders; i++)
  1211. X        fixchecksum(&headers[i], &headers[i].Checksum);
  1212. X
  1213. X    /*
  1214. X     *        Finally, write all the file blocks back to disk. Note that
  1215. X     *        they are written back to disk in reverse order. This way, the
  1216. X     *        file header itself is the last thing to get written, so if an
  1217. X     *        error occurs before hand, it won't be left in an inconsistent
  1218. X     *        state.
  1219. X     */
  1220. X    chkabort();                        /* Give user a final chance to abort */
  1221. X    for (i = numheaders - 1; i >= 0; i--) {
  1222. X        if (!writeblock(&headers[i], headers[i].OwnKey)) {
  1223. X            print("Error writing file headers to disk\n");
  1224. X            cleanup(10);
  1225. X        }
  1226. X    }
  1227. X}
  1228. X
  1229. X
  1230. X/*
  1231. X *        mainline()
  1232. X *        ----------
  1233. X */
  1234. Xvoid main(argc,argv)
  1235. Xint argc;
  1236. Xchar **argv;
  1237. X{
  1238. X    unsigned int start, end;            /* Cylinder numbers */
  1239. X    char *p;
  1240. X
  1241. X#define NONUM(x) (!isdigit(argv[x][0]))
  1242. X
  1243. X    if (argc != 4 || NONUM(2) || NONUM(3)) {
  1244. X        help();
  1245. X        cleanup(10);
  1246. X    }
  1247. X
  1248. X    /*
  1249. X     *        Strip off trailing dir and filenames to get device name
  1250. X     */
  1251. X    pathname = argv[1];
  1252. X    strcpy(devname, pathname);
  1253. X
  1254. X    for (p = devname; *p && *p != ':'; p++)
  1255. X        ;
  1256. X    if (*p != ':') {
  1257. X        print("The pathname must include both a device and a filename.\n");
  1258. X        cleanup(10);
  1259. X    }
  1260. X    p++;            /* Skip over colon at end of device name */
  1261. X    *p = '\0';
  1262. X
  1263. X    if (strlen(pathname) <= strlen(devname)) {
  1264. X        print("The pathname must include both a device and a filename.\n");
  1265. X        cleanup(10);
  1266. X    }
  1267. X    start = atoi(argv[2]);
  1268. X    end   = atoi(argv[3]);
  1269. X
  1270. X    if (!GetVolume(devname, diskdev)) {
  1271. X        print2(devname, " is not a valid disk device\n");
  1272. X        cleanup(10);
  1273. X    }
  1274. X
  1275. X    if (start > end) {
  1276. X        print("Start track is greater than end track.\n");
  1277. X        cleanup(10);
  1278. X    }
  1279. X
  1280. X    if (end >= diskdev->numcyl) {
  1281. X        print3("Maximum end track on ", devname, " is ");
  1282. X        print2(numtostr(diskdev->numcyl - 1), ".\n");
  1283. X        cleanup(10);
  1284. X    }
  1285. X
  1286. X    if (!diskdev->isknown) {
  1287. X        print(
  1288. X"Sorry, only Old Filing System and Fast Filing System are supported.\n");
  1289. X        cleanup(10);
  1290. X    }
  1291. X
  1292. X    if (diskdev->blocksize != 512) {
  1293. X        print(
  1294. X"Sorry, only devices with 512 byte blocks can be handled at present.\n");
  1295. X        cleanup(10);
  1296. X    }
  1297. X
  1298. X    if (diskdev->numblocks > (25 * 4064)) {
  1299. X        print("Sorry, this version doesn't support drives > 50 Mb\n");
  1300. X        cleanup(10);
  1301. X    }
  1302. X
  1303. X    diskport = (MSGPORT *)DeviceProc(devname);
  1304. X    if (!diskport) {
  1305. X        print3("Can't locate process for device ", devname, "\n");
  1306. X        cleanup(10);
  1307. X    }
  1308. X
  1309. X    /*
  1310. X     *        Everything seems in order, so lets try and create the dummy file.
  1311. X     *        After creating it, we flush the disk buffers etc. to ensure that
  1312. X     *        the disk bitmap is current.
  1313. X     */
  1314. X    filehandle = Open(pathname, MODE_NEWFILE);
  1315. X    if (!filehandle) {
  1316. X        print3("Couldn't open file ", pathname, ".\n");
  1317. X        cleanup(10);
  1318. X    }
  1319. X    Close(filehandle); filehandle = NULL;
  1320. X    lock = Lock(pathname, ACCESS_READ);
  1321. X    if (!lock) {
  1322. X        print3("Strangely, file ", pathname, " can no longer be accessed.\n");
  1323. X        cleanup(314);    /* pi -- let's be weird */
  1324. X    }
  1325. X    filekey = ((struct FileLock *)BTOC(lock))->fl_Key;
  1326. X    flushdisk(diskport);
  1327. X
  1328. X    /*
  1329. X     *        Assuming everthing is still okay, the next step is to read in
  1330. X     *        the root block and do some checks to make sure we can do the
  1331. X     *        allocation.
  1332. X     */
  1333. X    opendev();
  1334. X    inhibit(diskport, TRUE);
  1335. X    inhibited = TRUE;
  1336. X    readrootblock();
  1337. X    if (rootblock->BitmapFlag != -1) {
  1338. X        print3("tfile: Bitmap for ", devname, " is not up to date.\n");
  1339. X        cleanup(10);
  1340. X    }
  1341. X
  1342. X    /*
  1343. X     *        Read in bitmap, and mark all the blocks on the desired tracks
  1344. X     *        as in-use. If any of these blocks are already in use, then
  1345. X     *        abort with an error.
  1346. X     */
  1347. X    readbitmap();
  1348. X    if (!filltracks(start, end)) {
  1349. X        print3("Tracks ",numtostr(start)," to ");
  1350. X        print2(numtostr(end)," contain AmigaDOS data.\n");
  1351. X        cleanup(10);
  1352. X    }
  1353. X
  1354. X    /*
  1355. X     *        Now allocate file header blocks to store the AmigaDOS pointers
  1356. X     *        to each block in the reserved tracks in. The memory copy of
  1357. X     *        the bitmap is modified to reflect these additional blocks.
  1358. X     *        Then the new blocks are written back to disk, and the
  1359. X     *        file header of the existing file is updated to reflect the
  1360. X     *        additional data blocks.
  1361. X     */
  1362. X    createfileheaders(filekey,start,end);
  1363. X
  1364. X    /*
  1365. X     *        Everything is now complete, so all that remains to be done
  1366. X     *        is to write back the new bitmap, update the root block and
  1367. X     *        exit.
  1368. X     */
  1369. X    writebitmap();
  1370. X    cleanup(0);
  1371. X}
  1372. END_OF_FILE
  1373. if test 38195 -ne `wc -c <'src/tfile.c'`; then
  1374.     echo shar: \"'src/tfile.c'\" unpacked with wrong size!
  1375. fi
  1376. # end of 'src/tfile.c'
  1377. fi
  1378. echo shar: End of archive 2 \(of 2\).
  1379. cp /dev/null ark2isdone
  1380. MISSING=""
  1381. for I in 1 2 ; do
  1382.     if test ! -f ark${I}isdone ; then
  1383.     MISSING="${MISSING} ${I}"
  1384.     fi
  1385. done
  1386. if test "${MISSING}" = "" ; then
  1387.     echo You have unpacked both archives.
  1388.     rm -f ark[1-9]isdone
  1389. else
  1390.     echo You still need to unpack the following archives:
  1391.     echo "        " ${MISSING}
  1392. fi
  1393. ##  End of shell archive.
  1394. exit 0
  1395. -- 
  1396. Submissions to comp.sources.amiga and comp.binaries.amiga should be sent to:
  1397.     amiga@cs.odu.edu    
  1398. or    amiga@xanth.cs.odu.edu    ( obsolescent mailers may need this address )
  1399. or    ...!uunet!xanth!amiga    ( very obsolescent mailers need this address )
  1400.  
  1401. Comments, questions, and suggestions s should be addressed to ``amiga-request''
  1402. (only use ``amiga'' for submissions) at the above addresses.
  1403.